package com.xxjqr.rbac.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageInfo;
import com.xxjqr.rbac.auth.JwtTokenUtil;
import com.xxjqr.rbac.auth.JwtUser;
import com.xxjqr.rbac.auth.MyUserDetailsService;
import com.xxjqr.rbac.entity.dto.UserDto;
import com.xxjqr.rbac.entity.dto.UserLoginDto;
import com.xxjqr.rbac.entity.dto.UserPutDto;
import com.xxjqr.rbac.entity.pojo.TbUser;
import com.xxjqr.rbac.entity.pojo.TbUserRoleRel;
import com.xxjqr.rbac.entity.vo.MenuListVo;
import com.xxjqr.rbac.entity.vo.UserLoginVo;
import com.xxjqr.rbac.entity.vo.UserVo;
import com.xxjqr.rbac.enums.CodeMsgEnum;
import com.xxjqr.rbac.enums.StatusEnum;
import com.xxjqr.rbac.exception.CommonException;
import com.xxjqr.rbac.mapper.TbUserMapper;
import com.xxjqr.rbac.mapper.TbUserRoleRelMapper;
import com.xxjqr.rbac.service.TbMenuService;
import com.xxjqr.rbac.service.TbUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxjqr.rbac.util.SnowIdUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 丁昌江
 * @since 2021-02-26
 */
@Service
@AllArgsConstructor
public class TbUserServiceImpl extends ServiceImpl<TbUserMapper, TbUser> implements TbUserService {

    private final TbUserMapper userMapper;
    private final TbUserRoleRelMapper userRoleRelMapper;
    private final BCryptPasswordEncoder passwordEncoder;
    private final MyUserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    private final TbMenuService menuService;

    @Override
    public PageInfo<UserVo> getUsers(String name, String mobile, StatusEnum status, String createTime, String endTime, List<Long> deptIds) {
        return PageInfo.of(userMapper.getUsers(name, mobile, status, createTime, endTime, deptIds));
    }


    @Override
    @Transactional
    public Boolean editUser(UserPutDto userPutDto) {

        Long userId = userPutDto.getId();
        List<Long> paramRoleIds = userPutDto.getRoleIds();

        TbUser tbUser = new TbUser();
        BeanUtils.copyProperties(userPutDto, tbUser);

        //更新密码，因为功能是独立的，所以是更新密码的话，直接返回即可
        if (!StrUtil.isEmpty(tbUser.getPassword())) {
            tbUser.setPassword(passwordEncoder.encode(tbUser.getPassword()));
            return updateById(tbUser);
        }


        //获取该用户数据库中的角色，跟传递过来的参数比较求差值得到欲删除的角色
        List<Long> roleIds = userRoleRelMapper.selectList(new LambdaQueryWrapper<TbUserRoleRel>()
                .eq(TbUserRoleRel::getUserId, userId))
                .stream()
                .map(TbUserRoleRel::getRoleId)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(roleIds)) {
            if (!CollectionUtils.isEmpty(paramRoleIds)) {
                roleIds.removeAll(paramRoleIds);
            }

            if (roleIds.size() > 0) {
                userRoleRelMapper.delete(new LambdaQueryWrapper<TbUserRoleRel>().eq(TbUserRoleRel::getUserId, userId).in(TbUserRoleRel::getRoleId, roleIds));
            }
        }

        //遍历判断该角色是否存在，存在着开启，不存在则创建
        if (CollectionUtils.isEmpty(paramRoleIds)) {
            return updateById(tbUser);
        }
        for (Long roleId : paramRoleIds) {
            TbUserRoleRel tbUserRoleRel = userRoleRelMapper.selectOne(new LambdaQueryWrapper<TbUserRoleRel>()
                    .eq(TbUserRoleRel::getUserId, userId)
                    .eq(TbUserRoleRel::getRoleId, roleId));
            if (tbUserRoleRel == null) {
                tbUserRoleRel = new TbUserRoleRel();
                tbUserRoleRel.setId(SnowIdUtil.nextId());
                tbUserRoleRel.setUserId(userId);
                tbUserRoleRel.setRoleId(roleId);
                userRoleRelMapper.insert(tbUserRoleRel);
            }
        }

        return updateById(tbUser);
    }

    @Override
    @Transactional
    public Boolean addUser(UserDto userDto) {
        TbUser tbUser = new TbUser();
        BeanUtils.copyProperties(userDto, tbUser);
        tbUser.setPassword(passwordEncoder.encode(userDto.getPassword()));
        tbUser.setId(SnowIdUtil.nextId());
        TbUserRoleRel tbUserRoleRel = new TbUserRoleRel();
        for (Long roleId : userDto.getRoleIds()) {
            tbUserRoleRel.setId(SnowIdUtil.nextId());
            tbUserRoleRel.setUserId(tbUser.getId());
            tbUserRoleRel.setRoleId(roleId);
            userRoleRelMapper.insert(tbUserRoleRel);
        }
        return save(tbUser);
    }

    @Override
    public UserLoginVo login(UserLoginDto loginDto, HttpServletRequest request) {
        JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(loginDto.getUsername());
        if (jwtUser == null) {
            throw CommonException.generate(CodeMsgEnum.USER_NOTFOUND);
        }
        if (!passwordEncoder.matches(loginDto.getPassword(), jwtUser.getPassword())) {
            throw CommonException.generate(CodeMsgEnum.PASSWORD_ERROR);
        }

        //登录校验成功后，把登录成功的信息放到springsecurity上下文中
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authentication);

        String token = jwtTokenUtil.generateToken(jwtUser);

        Long userId = jwtUser.getId();

        //菜单数据
        //Map<String,List> menuMap = menuService.getUserMenus(userId);
        List<MenuListVo> menuVoList = menuService.getUserMenus(userId);
        //List<MenuVo> menuVoList = menuMap.get("menuVoList");
        Collections.sort(menuVoList);
        return new UserLoginVo(userId,jwtUser.getUsername(),token,menuVoList);
    }

    //public static void main(String[] args) {
    //    ArrayList<JwtUser> list = new ArrayList<>();
    //    JwtUser jwtUser = new JwtUser();
    //    jwtUser.setId(1L);
    //    jwtUser.setUsername("andy");
    //    list.add(jwtUser);
    //    System.out.println(list.toString());
    //}
}
